Migrate to generated TypeScript client from ros2_medkit_clients#53
Merged
Migrate to generated TypeScript client from ros2_medkit_clients#53
Conversation
There was a problem hiding this comment.
Pull request overview
Migrates the UI from the hand-maintained SovdApiClient to the generated @selfpatch/ros2-medkit-client-ts client, centralizing API path routing and response-shape normalization in the store layer to keep component interfaces stable.
Changes:
- Replaced the custom REST client with a generated OpenAPI client and added typed dispatch helpers (
api-dispatch.ts) for entity-type routing. - Introduced pure response mappers (
transforms.ts) and corresponding unit tests to reshape gateway responses into UI-friendly types. - Updated the Zustand store and multiple components to use store actions instead of direct client calls; removed the old client implementation/tests.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lib/utils.ts | Adds shared helpers (fault entity type mapping, byte/duration formatting) previously living in the old client. |
| src/lib/utils.test.ts | Adds unit coverage for new utility helpers. |
| src/lib/types.ts | Re-exports select generated-client schema types and keeps manual UI types. |
| src/lib/transforms.ts | Adds response transformation utilities extracted from the old client logic. |
| src/lib/transforms.test.ts | Adds unit tests validating the new transformation behaviors. |
| src/lib/api-dispatch.ts | Adds per-entity-type OpenAPI path dispatch wrappers (apps/components/areas/functions). |
| src/lib/store.ts | Switches to generated client, wires dispatch/transforms, updates fault streaming, and adds component-facing store actions. |
| src/lib/sovd-api.ts | Removes the legacy hand-maintained REST client implementation. |
| src/lib/sovd-api.test.ts | Removes tests for the legacy REST client. |
| src/components/TopicPublishForm.tsx | Switches topic publishing to store action instead of direct client usage. |
| src/components/DataPanel.tsx | Removes client prop dependency and delegates publish behavior to store actions. |
| src/components/EntityDetailPanel.tsx | Updates resource-count and data-loading flow to use store actions. |
| src/components/EntityResourceTabs.tsx | Migrates per-tab resource loads to store actions and store-backed configuration state. |
| src/components/AppsPanel.tsx | Replaces direct client calls with store actions for app resources. |
| src/components/FunctionsPanel.tsx | Replaces direct client calls with store actions for function resources and config counts. |
| src/components/FaultsPanel.tsx | Migrates faults list/detail/clear behaviors to store actions and shared utils mapper. |
| src/components/FaultsDashboard.tsx | Migrates fault detail loading to store action and shared utils mapper. |
| src/components/RosbagDownloadButton.tsx | Switches downloads to store action and moves formatting helpers to utils. |
| src/components/SnapshotCard.tsx | Moves formatting helper imports from old client to utils. |
| src/components/OperationsPanel.tsx | Updates SovdResourceEntityType import location post-migration. |
| src/components/ConfigurationPanel.tsx | Updates SovdResourceEntityType import location post-migration. |
| src/components/ServerInfoPanel.tsx | Switches server info fetches to store actions instead of direct client calls. |
| package.json | Adds generated client dependency (and OpenAPI fetch dependency). |
| .npmrc | Configures scoped registry for @selfpatch packages. |
Add generated TypeScript client and openapi-fetch peer dependency. Configure .npmrc for GitHub Packages registry.
Create standalone transform functions for fault, operations, data, configurations, and bulk data responses. These handle x-medkit vendor extension extraction and field renaming.
Move formatBytes, formatDuration, and mapFaultEntityTypeToResourceType to utils.ts in preparation for sovd-api.ts removal.
Add import of components schema from @selfpatch/ros2-medkit-client-ts. Re-export VersionInfo and GenericError (as SovdError) from generated schema where shapes match. Other types stay manual due to significant API differences - transforms.ts handles runtime mapping.
Route generic (entityType, entityId) calls to the correct per-entity typed API paths required by openapi-fetch. Covers configurations, data, operations, executions, faults, and bulk data.
Replace all SovdApiClient method calls with typed openapi-fetch GET/POST/PUT/DELETE calls via api-dispatch helpers. Migrate SSE fault streaming from EventSource to SseStream async iterable. Remove baseEndpoint from AppState (URL normalization is automatic).
Add fetchEntityData, fetchEntityOperations, listEntityFaults, getFaultWithEnvironmentData, publishToEntityData, getServerCapabilities, getVersionInfoAction, downloadBulkData, getFunctionHosts, and prefetchResourceCounts actions.
…th store actions Migrate 14 components from direct SovdApiClient usage to store actions: - Group 1 (import-only): SnapshotCard, ConfigurationPanel, OperationsPanel - Group 2 (import + client replacement): RosbagDownloadButton, FaultsPanel, FaultsDashboard, EntityResourceTabs, AppsPanel, FunctionsPanel, ServerInfoPanel - Group 3 (remove client prop chain): DataPanel, TopicPublishForm, EntityDetailPanel All imports updated from @/lib/sovd-api to @/lib/types or @/lib/utils. All direct client.method() calls replaced with store actions. Updated RosbagDownloadButton test to mock store action instead of client.
Delete sovd-api.ts (~2087 lines) and its tests. All API calls now go through the generated @selfpatch/ros2-medkit-client-ts client via the Zustand store and api-dispatch helpers.
- App.tsx: remove baseEndpoint from store selector and connect() call - ServerConnectionDialog.tsx: remove base endpoint input field entirely (generated client normalizes URLs automatically) - store.ts: remove unused dynamic import, use store serverUrl instead of fragile type cast for download URL construction
e1007d4 to
c7f8997
Compare
The publish UI was showing even when disconnected because the client null check was dropped during migration. Replaced with isConnected store check.
…lback fetch - refreshSelectedEntity: use selectedEntity.type/id instead of path parsing - handleTopicSelection: find parent entity from tree, fetch via getEntityDataItem - fetchEntityFromApi: use depth heuristic instead of treating path[0] as entityType - downloadBulkData: add encodeURIComponent for path segments - Replace all dynamic imports with static imports
- Add entity type field to raw API responses (areas, components, apps) - Fix topic detail: transform raw DataItem to ComponentTopic for schema - Fix SSE fault stream: pass fetch.bind(globalThis) to createMedkitClient - Fix fetchEntityFromApi: parse /data/ and /operations/ resource paths - Fix snapshot duplicate React keys in FaultsDashboard and FaultsPanel - Fix getFaultWithEnvironmentData: single request, no brute-force fallback - Remove console.log info lines, add console.error on all error paths - Rename browser tab to ros2_medkit Web UI - Remove all dynamic imports, use static imports only
- ServerConnectionDialog: title and description - EmptyState: connection prompt text - ServerInfoPanel: fallback server name - store.ts: fallback in loadRootEntities - Fix auto-connect loop in React strict mode - Add @testing-library/dom to fix peer dep resolution
Prevents UI from getting stuck in 'Connecting...' state when server doesn't respond. Shows timeout error message and re-enables input.
7 tasks
Remove .npmrc GitHub Packages config - package is now published to npmjs.com (public, no auth required for install).
Add .serena/ to .gitignore - tool config should not be committed. Run prettier on all files that failed CI formatting check.
- Fix || to ?? in transformFaultsResponse count (zero treated as falsy) - Remove debug console.warn from fetchEntityData - Add error handling to publishToEntityData (try/catch + toast) - Fix SSE stream error recovery: clear faultStreamCleanup so polling fallback can activate instead of silent data staleness - Fix entity type pluralization: use mapping instead of naive 's' append - Fix downloadBulkData: use normalizeBaseUrl, add AbortController timeout - Fix EntityResourceTabs: use ref for loadedTabs to prevent unnecessary useCallback/useEffect re-runs
api-dispatch.test.ts: covers all 19 dispatch functions across all 4 entity types, verifying correct path routing and parameter mapping. store-helpers.test.ts: covers pure helper functions (toTreeNode, updateNodeInTree, findNode, inferEntityTypeFromDepth, parseTreePath) with edge cases. Exports 5 previously-private helpers for testability. Total test count: 107 -> 243
When the gateway returns no areas (empty list), load components directly under the server node instead of showing an empty tree. Hierarchy with areas: Server -> Areas -> Components -> Apps Hierarchy without: Server -> Components -> Apps
Components can have both subcomponents and apps (hosts) as children. For example, a hypervisor component may host guest OS subcomponents and also run its own monitoring apps directly. loadChildren now fetches subcomponents and hosts in parallel via Promise.all, showing subcomponents first then apps in the tree.
- Fix SSE faultData null guard: check typeof before 'in' operator - Move cleanup() declaration before consume() to prevent ReferenceError - Use || -> ?? for fault payload extraction - Fix timestamp overflow: Date.now() * 1_000_000 exceeds MAX_SAFE_INTEGER - Fix handleTopicSelection: transform raw API response through transformDataResponse instead of raw cast to ComponentTopic - Move @testing-library/dom from dependencies to devDependencies
mfaferek93
reviewed
Apr 2, 2026
mfaferek93
reviewed
Apr 2, 2026
mfaferek93
reviewed
Apr 2, 2026
mfaferek93
reviewed
Apr 2, 2026
… guards - Eliminate duplicate getEntityData call: prefetchResourceCounts no longer fetches data count, EntityDetailPanel uses fetchEntityData result length instead - Extract entity_type from raw fault data when available, fall back to 'app' (gateway doesn't include entity_type yet) - Add runtime guards to all 6 transform functions: return safe defaults for null/undefined/non-object input instead of crashing
mfaferek93
approved these changes
Apr 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
Summary
Replace the hand-maintained REST client (
sovd-api.ts, ~2087 lines) with the generated TypeScript client from@selfpatch/ros2-medkit-client-ts. The Zustand store absorbs all API translation via dispatch helpers and response transforms, keeping the component layer's public interface unchanged.Key changes:
sovd-api.ts(2087 lines) and its testsapi-dispatch.ts(524 lines) - entity-type routing for openapi-fetch typed pathstransforms.ts(362 lines) - response reshaping (field renames, x-medkit extraction)store.ts- swapped SovdApiClient for MedkitClient, migrated SSE fault streaming to SseStream async iterableIssue
Type
Testing
npm test)npm run typecheck)npm run lint)Checklist
npm run lint)npm run build)